'''
This example illustrates how pyrwi simplifies a lot of data acqusition
tasks.
'''
import sys
#Include the parent directory in the search path so that Python can 
#find pyrwi
sys.path.append("..") 

#Load the nidaqmx library and name it DAQmx so that all functions
#are available as DAQmx.function_name
import nidaqmx as DAQmx
import pyrwi #Load the PyRWI module so we can use its helpers

#pyFLTK is used to build the actual GUI
#See http://pyfltk.sourceforge.net/docs/CH0_Preface.html for more info
import fltk 

#Load the math library to give us arrays and math functions
import scipy as sp


class LabWindow (pyrwi.RWI_Window):
    '''
    We make own window class so we can customize the window how we want.
    Note that this window inherits from pyrwi.RWI_Window.
    pyrwi.RWI_Window creates a lot of things for you. It automatically
    includes a menu and a log. It also does some background work to
    allow DAQmx to raise callbacks.
    '''
    def __init__(self, w, h, label):
        '''
        Create the window and place puttons on it.
        '''
        #Call the parent constructor
        pyrwi.RWI_Window.__init__(self, w, h, label)
        
        #Note there is no menu or log declarations here. Inheriting from
        #pyrwi.RWI_Window does that for us.
        
        #Create teh same button stack as was in gui_basic.py, just
        #in a different order and they are in a row instead of column.
        stack = pyrwi.Fl_Button_Stack(5,50,90,25,pdx=0.25)
        self.run_btn = stack.addBtn("Run",self.btn_run_cb,"light")
        stack.addBtn("Clear",self.btn_clear_cb)
        stack.addBtn("Add",self.btn_addData_cb)
        
        #Create a plot so I can show the data I read
        self.myPlot = pyrwi.Fl_Plot(110,90, 400,200, "DAQ Reading")
    
    #
    # Logic Code
    #
    def configureTask(self) :
        '''
        This creates a new DAQmx task and configures that task.
        The task is stored in the class as self.task.
        '''
        self.Fs = 1000.0 # Samples / second
        self.nSamples = 100 #Number of samples to read into DAQ buffer
                            # before calling Python to empty the buffer
        
        self.task = DAQmx.CreateTask("ContAcq")             #Create a new task
        DAQmx.CreateAIVoltageChan(self.task,"Dev1/ai0","",\
                DAQmx.Val_Cfg_Default,-10.0,10.0,\
                DAQmx.Val_Volts,None)                       #Configure to read a voltage

        #Configure a continuous clock
        DAQmx.CfgSampClkTiming(self.task,"",self.Fs,\
                DAQmx.Val_Rising,DAQmx.Val_ContSamps,\
                self.nSamples)
        
        #The pyrwi.ReadChannelHelper handles the DAQ reads for you.
        #With every read it updates the plot and also takes care of
        #saving data to a file for you.
        self.readHelper = pyrwi.ReadChannelHelper(self.task, self.myPlot, 'test.csv', buf_time=1.0)
        #buf_time limits the plot to the last second of data. All data
        #will be written to the file though.
        
        #Tell DAQmx who to call every time the buffer fills.
        DAQmx.RegisterEveryNSamplesEvent(self.task, DAQmx.Val_Acquired_Into_Buffer,\
                self.nSamples,0,DAQmx.ReadAnalogF64_cb, self.readHelper.cb_AnalogRead)
        #The 5th & 6th arguments work together. The 6th is a Python function
        #that handles reading from the buffer. The 5th is a C function
        #in the nidaqmx library that determines how the Python function
        #will be called
        #
        #For the 5th argument you must supply one of three functions:
        #1) DAQmx.EveryNCallPython_cb - This is the generic call back
        #       the Python function will have to empty the buffer on its
        #       own. This can be slow.
        #2) DAQmx.ReadAnalogF64_cb - This is optimized for analog reads
        #       it will read analog data from the buffer for you
        #       and pass the data as a list to the Python function
        #3) DAQmx.ReadDigitalU32_cb - This is like ReadAnalogF64_cb
        #       but reads 32bit digital data instead
        #
        #Typically you have to write your own Python function for the 6th
        #argument, but the pyrwi.ReadChannelHelper provides a pre-written
        #function for you and that is what is used here.
        
    #
    # Event Call Backs
    #
    def btn_run_cb(self, event) :
        '''
        This function is called when the Run button is pressed.
        '''
        self.log.note("Pushed! Value is %d" % self.run_btn.value())
        
        if self.run_btn.value() == 1 :
            #The button just turned on
            self.log.note("Starting task")
            
            self.configureTask() #Setup the task
            DAQmx.StartTask(self.task) #start reading data
        else :
            #The button was just turned off
            
            #Data be read continuously until we stop the task
            DAQmx.StopTask(self.task)
            
            #Delete the task
            DAQmx.ClearTask(self.task)
    
    def btn_clear_cb(self, event):
        '''
        This function is called when the Clear button is pressed.
        '''
        self.log.note("clear something!")
        self.myPlot.clear()
        
    def btn_addData_cb(self, event):
        '''
        This function is called when the Add button is pressed.
        In this function will will make a single analog measurement.
        '''        
        Fs = 10000.0
        nSamples = 1000
        
        #Create a configure a new task for this measurement.
        taskHandle = DAQmx.CreateTask("AnalogAcq")
        DAQmx.CreateAIVoltageChan(taskHandle,"Dev1/ai0","",DAQmx.Val_Cfg_Default,-10.0,10.0,DAQmx.Val_Volts,None)
        DAQmx.CfgSampClkTiming(taskHandle,"",Fs,DAQmx.Val_Rising,DAQmx.Val_FiniteSamps,nSamples)

        #Read the data right now
        DAQmx.StartTask(taskHandle)
        
        #Get the data from the DAQ buffer
        data = DAQmx.ReadAnalogF64(taskHandle,nSamples,10.0,DAQmx.Val_GroupByChannel,nSamples,None)
        DAQmx.StopTask(taskHandle)
        DAQmx.ClearTask(taskHandle)
        
        #Make a nice time vector for plotting the data
        x = sp.arange(0,nSamples/Fs, 1.0/Fs)
        
        #Plot the data
        self.myPlot.plot(x,data)

if __name__ == "__main__" :
    win = LabWindow(600, 500, "MyWindow")
    win.show(1, sys.argv)

    fltk.Fl.run()
